/*****************************************************************
*
*	Article:
*		How to get IHTMLDocument2 from a HWND
*
*	Authors:
*		Miles Chen (stainboyx@hotmail.com)
*
*	Reference:
*		http://support.microsoft.com/kb/249232
*		Note: there is a bug in the above link. To fix it, I just
*		replace IID_IHTMLDocument2 with IID_IHTMLDocument in the KB code
*
*	Build:
*		cl /EHsc /Fosimple cpp-get-ie-document-from-hwnd.cpp
*
*****************************************************************/
#include <atlbase.h>
#include <mshtml.h>
#include <oleacc.h>

#include <memory>
#include <iostream>
#include <string>


using namespace std;

CComQIPtr<IHTMLDocument2> GetDocInterface(HWND hWnd) ;

int main()
{
	CoInitialize( NULL );
	//
	CComQIPtr<IHTMLDocument2> spDoc = GetDocInterface(FindWindowW(L"IEFrame", NULL));
	if(spDoc)
	{
		cout << "IHTMLDocument2 interface has been retrieved" << endl;
		//TODO with IHTMLDocument2*
	}
	else
	{
		cout << "Cannot find an active IHTMLDocument2 interface" << endl;
	}
	// Make sure release smart pointer before CoUninitialize()
	spDoc.Release();	
	//
	CoUninitialize();
	return 0;
}

BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)
{
	TCHAR	buf[100];

	::GetClassName( hwnd, (LPTSTR)&buf, 100 );
	if ( _tcscmp( buf, _T("Internet Explorer_Server") ) == 0 )
	{
		*(HWND*)lParam = hwnd;
		return FALSE;
	}
	else
		return TRUE;
}

CComQIPtr<IHTMLDocument2> GetDocInterface(HWND hWnd) 
{
	CComQIPtr<IHTMLDocument2> spDoc;

	// Explicitly load MSAA so we know if it's installed
	HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
	if ( hInst != NULL )
	{
		if ( hWnd != NULL )
		{
			HWND hWndChild=NULL;
			// Get 1st document window
			::EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild );
			if ( hWndChild )
			{				
				LRESULT lRes;
			
				UINT nMsg = ::RegisterWindowMessageW(L"WM_HTML_GETOBJECT");
				::SendMessageTimeoutW( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );

				LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, "ObjectFromLresult" );
				if ( pfObjectFromLresult != NULL )
				{
					HRESULT hr;
					hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument2, 0, (void**)&spDoc );
					if ( SUCCEEDED(hr) )
					{
						// Set the title of current page
						spDoc->put_title( CComBSTR(L"Chinese people are great!") );
					}
				}
			} // else document not ready
		} // else Internet Explorer is not running
		::FreeLibrary( hInst );
	} // else Active Accessibility is not installed

	// Call CComQIPtr<T>'s copy constructor to pass the local variable
	return spDoc;
}